﻿using System;
using System.IO;
using Fetches.Fetch.Dto;
using Fetches.Fetch.Utils;
using Newtonsoft.Json;

namespace Fetches.Fetch.PagePool
{
    public class OnDiskPagePool : LocalPagePool
    {
        private string _cachePath;
        private string _contentPath;
        private string _indexFile;

        public override void Initialize(string config, long uniqueId)
        {
            var basePath = config;
            if (string.IsNullOrEmpty(basePath))
            {
                basePath = @"D:\PagePool";
            }

            _cachePath = Path.Combine(basePath, uniqueId.ToString());
            _contentPath = Path.Combine(basePath, "data");
            _indexFile = Path.Combine(_cachePath, "index.txt");
            Directory.CreateDirectory(_cachePath);
            Directory.CreateDirectory(_contentPath);
            if (File.Exists(_indexFile))
            {
                foreach (var record in File.ReadAllLines(_indexFile))
                {
                    var sp = record.IndexOf("#");
                    var idx = Convert.ToInt32(record.Substring(0, sp));
                    var id = record.Substring(sp + 1);
                    PagesIndex.TryAdd(idx, id);
                    MaxOffset = idx;
                }
            }

        }

        public override ResponsePage Get(int offset)
        {
            return PagesIndex.TryGetValue(offset, out string pageId) ? Get(pageId) : null;
        }

        protected override void Store(ResponsePage responsePage)
        {
            lock (this)
            {
                var setting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
                string[] props = { "SourceCode", "LocalizedSourceCode" }; //排除掉
                setting.ContractResolver = new LimitPropsContractResolver(props, false);
                var data = JsonConvert.SerializeObject(responsePage, setting);

                var id = responsePage.TimeStamp + HashHelper.Md5(responsePage.Request.Url.OriginalString);//timestamp在前面便于排序,对Url计算hash时防止.com被当作文件类型
                File.WriteAllText(Path.Combine(_cachePath, id), data);
                var contentFile = Path.Combine(_contentPath, responsePage.ContentHash);
                if (!File.Exists(contentFile))
                {
                    File.WriteAllText(contentFile, responsePage.SourceCode);
                }

                //测试用
                if (!string.IsNullOrEmpty(responsePage.LocalizedSourceCode))
                {
                    var localSourceFile = contentFile + ".html";
                    File.WriteAllText(localSourceFile, responsePage.LocalizedSourceCode);
                }

                var idx = PagesIndex.Count + 1;
                PagesIndex.TryAdd(idx, id);
                MaxOffset = idx;
                File.AppendAllLines(_indexFile, new[] { $"{idx}#{id}" });
            }

        }

        public override ResponsePage Get(string pageId)
        {
            var filename = Path.Combine(_cachePath, pageId);
            if (!File.Exists(filename))
            {
                return null;
            }
            var data = File.ReadAllText(filename);
            var page = JsonConvert.DeserializeObject<ResponsePage>(data);
            var contentFile = Path.Combine(_contentPath, page.ContentHash);
            page.SourceCode = File.ReadAllText(contentFile);
            return page;
        }

    }
}
